// 版权所有2012 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import "unsafe"

const (
	// 计划9环境设备
	envDir = "/env/"
	// 从目录中读取的缓冲区大小
	dirBufSize = 4096
	// 读取环境变量的缓冲区大小（可能会增长）
	envBufSize = 128
	// 9P目录项中名称字段的偏移量-请参阅syscall。UnmarshalDir（）
	nameOffset = 39
)

// Goenvs在开始执行时将Plan 9环境变量缓存到
// string array envs中，为操作系统提供初始内容。包围
// 对操作系统的后续调用。Setenv将更改此缓存，而不将
// 写回（可能是共享的）Plan 9环境，以便Setenv和Getenv 
// 与其他操作系统上的Posix语义一致。
// 对于Plan 9共享环境语义，可以使用操作系统，而不是Getenv（key）和
// Setenv（key，value）。ReadFile（“/env/”+key）和
// os。WriteFile（“/env/”+键，值，0666）。
// go:nosplit 
func goenvs() {
	buf := make([]byte, envBufSize)
	copy(buf, envDir)
	dirfd := open(&buf[0], _OREAD, 0)
	if dirfd < 0 {
		return
	}
	defer closefd(dirfd)
	dofiles(dirfd, func(name []byte) {
		name = append(name, 0)
		buf = buf[:len(envDir)]
		copy(buf, envDir)
		buf = append(buf, name...)
		fd := open(&buf[0], _OREAD, 0)
		if fd < 0 {
			return
		}
		defer closefd(fd)
		n := len(buf)
		r := 0
		for {
			r = int(pread(fd, unsafe.Pointer(&buf[0]), int32(n), 0))
			if r < n {
				break
			}
			n = int(seek(fd, 0, 2)) + 1
			if len(buf) < n {
				buf = make([]byte, n)
			}
		}
		if r <= 0 {
			r = 0
		} else if buf[r-1] == 0 {
			r--
		}
		name[len(name)-1] = '='
		env := make([]byte, len(name)+r)
		copy(env, name)
		copy(env[len(name):], buf[:r])
		envs = append(envs, string(env))
	})
}

// Dofiles读取用文件描述符fd打开的目录，对其中的每个文件名应用函数f 
// 。
// go:nosplit 
func dofiles(dirfd int32, f func([]byte)) {
	dirbuf := new([dirBufSize]byte)

	var off int64 = 0
	for {
		n := pread(dirfd, unsafe.Pointer(&dirbuf[0]), int32(dirBufSize), off)
		if n <= 0 {
			return
		}
		for b := dirbuf[:n]; len(b) > 0; {
			var name []byte
			name, b = gdirname(b)
			if name == nil {
				return
			}
			f(name)
		}
		off += int64(n)
	}
}

// Gdirname返回目录项缓冲区中的第一个文件名、
// 以及包含剩余目录项的一个片段。
// 如果缓冲区不是以有效的目录项开头，则返回的名称为零。
// go:nosplit 
func gdirname(buf []byte) (name []byte, rest []byte) {
	if 2+nameOffset+2 > len(buf) {
		return
	}
	entryLen, buf := gbit16(buf)
	if entryLen > len(buf) {
		return
	}
	n, b := gbit16(buf[nameOffset:])
	if n > len(b) {
		return
	}
	name = b[:n]
	rest = buf[entryLen:]
	return
}

// Gbit16从b中读取一个16位的小端二进制数，并将其返回
// b的剩余部分。
// go:nosplit 
func gbit16(b []byte) (int, []byte) {
	return int(b[0]) | int(b[1])<<8, b[2:]
}
